# This tutorial will demonstrate some implementations of nested control
# structures in Python. Nested structures very quickly become complicated
# and hard to decipher. Python requires you to indent your code properly
# which is an advantage because it makes the code easier to read/follow.
# In the while loop tutorial we should how you could calculate factorials
# using while loops. Suppose you wanted to restrict users to inputing only
# integer values of n. You can do this by placing your while loop inside
# an if statement. The if statement will be used to check for valid
# values of n.
# First, I introduce the % function. y % x outputs the remainder of
# y/x.
x = 5 % 2
print('5/2 has a remainder of', x)
x = 4 % 2
print('4/2 has a remainder of', x)
5/2 has a remainder of 1 4/2 has a remainder of 0
# So, here is our first nested set of control structures.
n = 4.3
if n % 1 == 0:
print('n =', n)
factorial = 1
while n > 1:
factorial = factorial*n
n -= 1
print('n! =', factorial)
else:
print('Invalid entry: n is noninteger.')
Invalid entry: n is noninteger.
# Notice that we can still trick the system into producing nonsense by
# entering a negative integer.
n = -4
if n % 1 == 0:
print('n =', n)
factorial = 1
while n > 1:
factorial = factorial*n
n -= 1
print('n! =', factorial)
else:
print('Invalid entry: n is noninteger.')
n = -4 n! = 1
# To fix this problem, we need to check that n is an integer AND positive.
# We will use 'and' to add another condition to our if statement.
# We will also implement some elseif statements so that we can present proper
# error messages.
#
# In the elseif statements != means 'not equal to' and <= means 'less than
# or equal to'. Try different entries for n. If you enter, for example, a
# string for n you'll get an error message from Python. As you can see,
# accounting for all the possible silly inputs users could enter requires a
# lot of thorough and careful programming!
n = 13
if n % 1 == 0 and n > 0:
print('n =', n)
factorial = 1
while n > 1:
factorial = factorial*n
n -= 1
print('n! =', factorial)
elif n == 0:
print('n =', n)
print('n! = 1')
elif n % 1 != 0 and n > 0:
print('Invalid entry: n is noninteger.')
elif n % 1 == 0 and n < 0:
print('Invalid entry: n negative.')
elif n % 1 != 0 and n < 0:
print('Invalid entry: n is noninteger and negative.')
n = 13 n! = 6227020800
# Now let's put our factorial code into a for loop so that we can calculate
# n! as a function of n.
import numpy as np
start = 0
finish = 25
ns = np.arange(start, finish + 1, 1)
print(ns)
facts = []
for i in ns:
if i % 1 == 0 and i > 0:
n = int(i)
factorial = 1
while n > 1:
factorial = factorial*n
n -= 1
facts = facts + [factorial]
elif i == 0:
facts = facts + [1]
elif i % 1 != 0 and n > 0:
print('Invalid entry: n is noninteger.')
elif i % 1 == 0 and n < 0:
print('Invalid entry: n negative.')
elif i % 1 != 0 and n < 0:
print('Invalid entry: n is noninteger and negative.')
facts
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25]
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000, 51090942171709440000, 1124000727777607680000, 25852016738884976640000, 620448401733239439360000, 15511210043330985984000000]
# We can now easily make a plot of n! vs n. Notice how sharply n! rises.
import matplotlib.pyplot as plt
plt.plot(ns, facts, 'bo', fillstyle = 'none')
plt.ylabel('n!')
plt.xlabel('n')
plt.title('linear-linear plot');
# Here's the same data on a log-log scale.
plt.loglog(ns, facts, 'ro', fillstyle = 'none')
plt.ylabel('n!');
plt.xlabel('n')
plt.title('log-log plot');
# Here, we compare n! to exp(n). Above about n = 5, n! passes exp(n) and
# continues to increase at a higher rate than exp(n).
# First, reproduce the factorial plot...
plt.loglog(ns, facts, 'ro', fillstyle = 'none')
plt.ylabel('n!');
plt.xlabel('n')
plt.title('log-log plot');
# ... the add the exponential data.
xx = np.arange(1, finish, 0.01)
yexp = np.exp(xx)
plt.loglog(xx, yexp, 'k--')
plt.legend(('n!', 'exp(n)'));
# Finally, here's an implementation of our nested control structures in
# which the user is prompted to enter in start and end values for the n!
# calculation and then the plot comparing n! and e^n is generated.
start = int(input("Enter an integer start value: "))
finish = int(input("Enter an integer end value: "))
ns = np.arange(start, finish + 1, 1)
facts = []
for i in ns:
if i % 1 == 0 and i > 0:
n = int(i)
factorial = 1
while n > 1:
factorial = factorial*n
n -= 1
facts = facts + [factorial]
elif i == 0:
facts = facts + [1]
elif i % 1 != 0 and n > 0:
print('Invalid entry: n is noninteger.')
elif i % 1 == 0 and n < 0:
print('Invalid entry: n negative.')
elif i % 1 != 0 and n < 0:
print('Invalid entry: n is noninteger and negative.')
Enter an integer start value: 1 Enter an integer end value: 120
# Here are plots of n! vs n...
plt.loglog(ns, facts, 'ro', fillstyle = 'none')
plt.ylabel('n!');
plt.xlabel('n')
plt.title('log-log plot')
# and exp(n) vs n
xx = np.arange(start, finish, 0.01)
yexp = np.exp(xx)
plt.loglog(xx, yexp, 'k--')
plt.legend(('n!', 'exp(n)'));